home *** CD-ROM | disk | FTP | other *** search
- Debugging
- Previous: <Context Dependency=>ContextDep> * Next: <Invocation=>Invocation> * Up: <Top=>!Root>
-
- #Wrap on
- {fH2}Debugging Your Parser{f}
-
- If a Bison grammar compiles properly but doesn't do what you want when it
- runs, the {fCode}yydebug{f} parser-trace feature can help you figure out why.
-
- To enable compilation of trace facilities, you must define the macro
- {fCode}YYDEBUG{f} when you compile the parser. You could use
- {fEmphasis}-DYYDEBUG=1{f} as a compiler option or you could put {fEmphasis}\#define
- YYDEBUG 1{f} in the C declarations section of the grammar file
- (\*Note <C Declarations=>CDeclarati>: The C Declarations Section). Alternatively, use the {fEmphasis}-t{f} option when
- you run Bison (\*Note <Invocation=>Invocation>: Invoking Bison). We always define {fCode}YYDEBUG{f} so that
- debugging is always possible.
-
- The trace facility uses {fCode}stderr{f}, so you must add {fCode}\#include
- <stdio.h>{f} to the C declarations section unless it is already there.
-
- Once you have compiled the program with trace facilities, the way to
- request a trace is to store a nonzero value in the variable {fCode}yydebug{f}.
- You can do this by making the C code do it (in {fCode}main{f}, perhaps), or
- you can alter the value with a C debugger.
-
- Each step taken by the parser when {fCode}yydebug{f} is nonzero produces a
- line or two of trace information, written on {fCode}stderr{f}. The trace
- messages tell you these things:
-
- #Indent +4
-
- • Each time the parser calls {fCode}yylex{f}, what kind of token was read.
-
-
- • Each time a token is shifted, the depth and complete contents of the
- state stack (\*Note <Parser States=>ParserStat>).
-
-
- • Each time a rule is reduced, which rule it is, and the complete contents
- of the state stack afterward.
-
- #Indent
-
- To make sense of this information, it helps to refer to the listing file
- produced by the Bison {fEmphasis}-v{f} option (\*Note <Invocation=>Invocation>: Invoking Bison). This file
- shows the meaning of each state in terms of positions in various rules, and
- also what each state will do with each possible input token. As you read
- the successive trace messages, you can see that the parser is functioning
- according to its specification in the listing file. Eventually you will
- arrive at the place where something undesirable happens, and you will see
- which parts of the grammar are to blame.
-
- The parser file is a C program and you can use C debuggers on it, but it's
- not easy to interpret what it is doing. The parser function is a
- finite-state machine interpreter, and aside from the actions it executes
- the same code over and over. Only the values of variables show where in
- the grammar it is working.
-
- The debugging information normally gives the token type of each token
- read, but not its semantic value. You can optionally define a macro
- named {fCode}YYPRINT{f} to provide a way to print the value. If you define
- {fCode}YYPRINT{f}, it should take three arguments. The parser will pass a
- standard I\/O stream, the numeric code for the token type, and the token
- value (from {fCode}yylval{f}).
-
- Here is an example of {fCode}YYPRINT{f} suitable for the multi-function
- calculator (\*Note <Mfcalc Decl=>MfcalcDecm>: Declarations for {fCode}mfcalc{f}):
-
- #Wrap off
- #fCode
- \#define YYPRINT(file, type, value) yyprint (file, type, value)
-
- static void
- yyprint (file, type, value)
- FILE \*file;
- int type;
- YYSTYPE value;
- \{
- if (type == VAR)
- fprintf (file, " %s", value.tptr->name);
- else if (type == NUM)
- fprintf (file, " %d", value.val);
- \}
- #f
- #Wrap on
-
-